/**
 * 上海中赢金融信息服务有限公司
 * Copyright (c) 2017-2027 Chinazyjr,Inc.All Rights Reserved.
 */

package com.sys.midware.mail.core;

import java.io.File;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import com.sys.midware.assist.utils.Assert;
import com.sys.midware.assist.utils.string.StringUtil;
import com.sys.midware.logger.Logger;
import com.sys.midware.logger.LoggerFactory;
import com.sys.midware.mail.config.MailConfig;
import com.sys.midware.mail.config.MailConfigUtil;

/**
 * <b>ClassName:</b> BMail.java <br/>
 * <b>Description:</b> TODO <br/>
 * <b>Date:</b> 2015年10月27日 上午10:53:33<br/>
 * 
 * @author mobing
 * @version
 */
public class BMail {
    private static final Logger logger = LoggerFactory.getLogger(BMail.class);

    /**
     * 邮件连接会话
     */
    private Session session = null;

    /**
     * 邮件配置属性
     */
    private Properties properties = System.getProperties();

    /**
     * 认证器
     */
    private Authenticator authenticator = null;

    /** 发送附件 **/
    private HashMap<String, String> mailAttachment = new HashMap<String, String>();

    public static BMail bmail = new BMail();

    public static synchronized BMail getInstance() {
        return bmail;
    }

    // mail配置
    private MailConfig mailConf = null;

    private BMail() {
        init();
    }

    public void init() {
        // 加载邮件配置
        mailConf = MailConfigUtil.initConfig();
        // 设置邮件发送服务器
        setSMTPHost(mailConf.getSmtpHost(), String.valueOf(mailConf.getSmtpPort()));
       
        // 是否ssl安全加密
        if (mailConf.isSSL()) {
            enableSSL(String.valueOf(mailConf.getSSLPort()));
        }
        // 是否需要认证
        if (mailConf.isAuth()) {
            enableAuth(mailConf.getFromUser(), mailConf.getFromPassword());
        }
        session = getSession(mailConf.isAuth());
        // 是否开启调式模式
        session.setDebug(mailConf.isDebug());
    }

    public void send(String subject, String content) {
        String fromAddress = mailConf.getFromUser();
        String toEmailAddresses = mailConf.getToUser();
        String ccEmailAddresses = mailConf.getCcUser();
        if (StringUtil.isEmpty(toEmailAddresses)) {
            Assert.notNull(toEmailAddresses, "收件人不能为空");
        }
        List<String> toEmailAddressesList = Arrays.asList(toEmailAddresses.split(","));
        List<String> ccEmailAddressesList = null;
        if (StringUtil.isNotEmpty(ccEmailAddresses)) {
            ccEmailAddressesList = Arrays.asList(ccEmailAddresses.split(","));
        }
        send(fromAddress, toEmailAddressesList, ccEmailAddressesList, subject, content);
    }

    /**
     * Send email from specified from-address to specified to-addresses /
     * cc-addresses with given subject and content.
     * <p>
     * If already call addAttachment, the method will try to include them into
     * email body
     */
    public void send(String fromAddress, List<String> toEmailAddresses, List<String> ccEmailAddresses, String subject,
            String content) {
        MimeMessage message = new MimeMessage(session);
        MimeMultipart multipart = new MimeMultipart();
        try {
            message.setSubject(subject);
            message.setRecipients(Message.RecipientType.TO, emailToInternetAddressArray(toEmailAddresses));
            message.setRecipients(Message.RecipientType.CC, emailToInternetAddressArray(ccEmailAddresses));
            message.addFrom(InternetAddress.parse(fromAddress));
            message.setSentDate(new Date());
            BodyPart mainBody = new MimeBodyPart();
            mainBody.setContent(content, "text/plain;charset=UTF-8");
            multipart.addBodyPart(mainBody);
            for (Entry<String, String> e : mailAttachment.entrySet()) {
                BodyPart bodyPart = new MimeBodyPart();
                bodyPart.setDataHandler(new DataHandler(new FileDataSource(e.getKey())));
                bodyPart.setFileName(e.getValue());
                bodyPart.setHeader("Content-ID", e.getValue());
                multipart.addBodyPart(bodyPart);
            }
            message.setContent(multipart);
            message.saveChanges();
            Transport.send(message, message.getAllRecipients());
            mailAttachment.clear();
            logger.info("Send Mail success!");

        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }

    /**
     * Add attachment to email.
     */
    public void addAttachment(String filePath) {
        if (isStringEmpty(filePath)) {
            throw new RuntimeException("[Error] Attachment filepath is empty!");
        }
        mailAttachment.put(filePath, new File(filePath).getName());
    }

    /**
     * 设置smtp
     * 
     * @param
     * @return void
     */
    private void setSMTPHost(String smtpHost, String smtpPort) {
        if (smtpHost == null) {
            throw new RuntimeException("[Error] SMTP Host is empty!");
        }
        properties.setProperty("mail.smtp.port", smtpPort);
        properties.setProperty("mail.smtp.host", smtpHost);
    }

    /**
     * 获取邮件会话
     * 
     * @param
     * @return Session
     */
    private Session getSession(boolean needAuth) {
        mailAttachment.clear();
        return needAuth ? session = Session.getInstance(properties, authenticator) : Session.getInstance(properties);
    }

    /**
     * 启用认证
     * 
     * @param
     * @return void
     */
    private void enableAuth(final String username, final String password) {
        if (username == null || password == null) {
            throw new RuntimeException("[Error] Username or password is empty!");
        }
        properties.put("mail.smtp.auth", "true");
        authenticator = new Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password);
            }
        };
    }

    /**
     * 启用SSL
     * 
     * @param
     * @return void
     */
    private void enableSSL(String sslPort) {
        if (isStringEmpty(sslPort)) {
            throw new RuntimeException("[Error] SSL port is empty!");
        }
        properties.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        properties.setProperty("mail.smtp.socketFactory.fallback", "false");
        properties.setProperty("mail.smtp.port", sslPort);
        properties.setProperty("mail.smtp.socketFactory.port", sslPort);
    }

    private boolean isStringEmpty(String s) {
        return s == null || s.length() == 0;
    }

    private InternetAddress[] emailToInternetAddressArray(List<String> email) throws AddressException {
        if (email == null || 0 == email.size()) {
            return new InternetAddress[0];
        }
        InternetAddress[] addresses = new InternetAddress[email.size()];
        for (int i = 0; i < email.size(); i++) {
            addresses[i] = new InternetAddress(email.get(i));
        }
        return addresses;
    }

    public static void main(String[] args) {
//        List<String> to = new ArrayList<String>();
//        to.add("mobing@b5m.com");
//        // new BMail().send("junjiemail@126.com", to, null, "测试外部邮箱", "正文");
//
//        List<String> cc = new ArrayList<String>();
//        cc.add("daxian@b5m.com");
//        new BMail().send("ispider-data@b5m.com", to, cc, "测试邮件组件", "正文");
        
        BMail.getInstance().send("再次测试", "内容");
    }

}
